<?php
/**
 * Created by PhpStorm.
 * User: CPR007
 * Date: 2020/12/25
 * Time: 9:56
 */
require_once './coreBase.php';

class  sendMoney extends coreBase {
    protected $_handleDate;

    protected $_isSendSql = "select status,handle_date from eb_vip_send_list where handle_date='%s'";
    protected $_userSql = "select uid,spread_uid from eb_user order by uid limit %s ";
    protected $_pinkSql = "select uid,sum(total_price) as totalPrice from eb_store_pink where pid > 0 and DATE_FORMAT(created,'%Y-%m-%d') = 'HANDLE_DATE' GROUP by uid";
    protected $_gradeSql = "select id,grade from eb_system_user_level where grade in (2,3,4)";
    protected $_uInfoSql = "select uid,now_money,`level` from eb_user where uid in (%s) ";
    protected $_reportSql = "select count(1) as user_num,sum(now_money) as money,sum(points) as points,sum(start_num) as start_num from eb_user";
    protected $_cacheKey = 'pt_user';

    private $_gradeInfo = [];
    private $_execStatus = [];

    public function __construct($handleDate = '') {
        parent::__construct();
        $this->_handleDate = !empty($handleDate) ? $handleDate : date('Y-m-d', strtotime('-1 days'));
        $this->_getDbInstance($this->_configInfo['db']);
        $this->getRedisInstance($this->_configInfo['redis']);
        $this->_checkIsSend();
        $this->_delUserCache();
        $this->_createUserCache();
        $this->_getGradeInfo();
    }

    //检测是否已经发放vip流水
    protected function _checkIsSend() {
        $_checkSql = sprintf($this->_isSendSql, $this->_handleDate);
        $query = self::$dbInstance->query($_checkSql);
        $rs = $query->fetchAll(PDO::FETCH_ASSOC);
        if (!empty($rs) && $rs[0]['status'] == 20) {
            $this->writeLog($this->_handleDate . 'vip流水已经发放', 2);
            exit;
        }
    }

    //删除用户缓存信息
    protected function _delUserCache() {
        if(!method_exists(self::$redisInstance,'del')){
            self::$redisInstance->delete($this->_cacheKey);
        }else{
            self::$redisInstance->del($this->_cacheKey);
        }

    }

    //生成用户缓存信息
    protected function _createUserCache() {
        $ind = 1;
        $stepNum = 3000;
        while (true) {
            $limitStr = ($ind - 1) * $stepNum . ',' . $stepNum;
            $_uSql = sprintf($this->_userSql, $limitStr);
            $query = self::$dbInstance->query($_uSql);
            $rs = $query->fetchAll(PDO::FETCH_ASSOC);
            if (!empty($rs)) {
                $uInfo = array_column($rs, 'spread_uid', 'uid');
                self::$redisInstance->hMset($this->_cacheKey, $uInfo);
                if (count($uInfo) < $stepNum) {
                    break;
                }
            } else {
                break;
            }
            $ind++;
        }
    }

    //获取各级别信息
    protected function _getGradeInfo() {
        $query = self::$dbInstance->query($this->_gradeSql);
        $rs = $query->fetchAll(PDO::FETCH_ASSOC);
        if (!empty($rs)) {
            $this->_gradeInfo = array_column($rs, 'grade', 'id');
        }
    }

    //公共方法调用
    public function _toSend() {
        $pinkSql = str_replace('HANDLE_DATE', $this->_handleDate, $this->_pinkSql);
        $query = self::$dbInstance->query($pinkSql);
        $rs = $query->fetchAll(PDO::FETCH_ASSOC);
        if (empty($rs)) {
            $this->writeLog('暂无数据需要处理', 1);
            exit;
        }
        if (self::$redisInstance->hlen($this->_cacheKey) < 1) {
            $this->writeLog('用户redis数据生成错误！', 2);
            exit;
        }
        try {
            self::$dbInstance->beginTransaction();
            foreach ($rs as $payInfo) {
                $this->_sendVipMoney($payInfo);
            }
            //记录发放记录
            $addLogSql = "insert into eb_vip_send_list (status,handle_date,send_time) VALUES  (20,'" . $this->_handleDate . "','" . date('Y-m-d H:i:s') . "')";
            $this->_execStatus[] = self::$dbInstance->exec($addLogSql);
            $report = $this->_reportData();
            $insertReportSql = "insert into eb_report (`day`,money,points,start_num,user_num) VALUES  ('" . $this->_handleDate . "',{$report['money']},{$report['points']},{$report['start_num']},{$report['user_num']})";
            $this->_execStatus[] = self::$dbInstance->exec($insertReportSql);
            if (!in_array(false, $this->_execStatus, true)) {
                $this->writeLog($this->_handleDate . '发放vip流水成功', 3);
                self::$dbInstance->commit();
                exit;
            }
            $this->writeLog($this->_handleDate . '发放vip流水失败', 2);
            self::$dbInstance->rollback();
            exit;
        } catch (\Throwable $e) {
            $this->writeLog('执行vip流水发放失败，错误信息:' . $e->getMessage(), 2);
            exit;
        }

    }

    protected function _reportData()
    {
        $query = self::$dbInstance->query($this->_reportSql);
        $report = $query->fetchAll(PDO::FETCH_ASSOC);
        return $report[0];
    }

    //下发vip奖励
    protected function _sendVipMoney($info) {
        $ind = 0;
        $uidList[] = $info['uid'];
        while ($ind < 100) {
            $pId = $this->_getParentId($uidList[count($uidList) - 1]);
            if (!$pId) {
                break;
            }
            if (in_array($pId, $uidList)) {
                break;
            } else {
                $uidList[] = $pId;
            }
            $ind++;
        }
        $this->writeLog('用户id:' . $info['uid'] . '当天参团总消费:' . $info['totalPrice'], 1);
        $this->_toSendMoney($info['uid'], $uidList, $info['totalPrice']);
    }

    //sql写入逻辑
    private function _toSendMoney($buyId, $uidList, $totalPrice) {
        if (empty($uidList)) return true;
        $uidStr = implode(',', $uidList);
        $uSql = sprintf($this->_uInfoSql, $uidStr);
        $query = self::$dbInstance->query($uSql);
        $uInfo = $query->fetchAll(PDO::FETCH_ASSOC);
        $allInfo = [];
        foreach ($uInfo as $v) {
            $allInfo[$v['uid']] = [
                'level' => $this->_gradeInfo[$v['level']]??1,
                'now_money' => $v['now_money'],
                'uid' => $v['uid']
            ];
        }
        $allTInfo = [];//严格按照 参团人->上级递进
        foreach ($uidList as $uid) {
            if (!empty($allInfo[$uid])) {
                $allTInfo[$uid] = $allInfo[$uid];
            }
        }
        unset($uInfo, $uInfo);
        $vipMoneyInfo = $this->getApplyMoney($totalPrice, array_column($allTInfo, 'level', 'uid'));
        $winInfo = $vipMoneyInfo['winInfo'];
        $equalInfo = $vipMoneyInfo['equalInfo'];
        //新增余额 和明细
        $nowTime = time();
        if (!empty($winInfo)) {
            foreach ($winInfo as $uid => $money) {
                $sql = "update eb_user set now_money=now_money+" . $money . " where uid=$uid";
                $balance = bcadd((string)$allTInfo[$uid]['now_money'], (string)$money, 2);
                $mark = 'VIP流水奖励' . $money . '元';
                $billSql = "insert into eb_user_bill (title,uid,pm,add_time,category,`type`,`number`,link_id,balance,mark) 
values ('VIP流水奖励',$uid,1,$nowTime,'now_money','system_add',$money,$buyId,$balance,'" . $mark . "')";
                $this->writeLog('用户id:' . $buyId . '参团返vip流水变动---余额变动sql:' . $sql . ",余额明细变动sql:" . $billSql, 1);
                $this->_execStatus[] = self::$dbInstance->exec($sql);
                $this->_execStatus[] = self::$dbInstance->exec($billSql);
            }
        }
        if (!empty($equalInfo)) {
            foreach ($equalInfo as $uid => $equalMoney) {
                if($equalMoney>0){
                    $sql = "update eb_user set now_money=now_money+" . $equalMoney . " where uid=$uid";
                    $balance = bcadd((string)$allTInfo[$uid]['now_money'], (string)$equalMoney, 2);
                    $mark = 'VIP3平级流水奖励' . $equalMoney . '元';
                    $billSql = "insert into eb_user_bill (title,uid,pm,add_time,category,`type`,`number`,link_id,balance,mark) 
values ('VIP3平级流水奖励',$uid,1,$nowTime,'now_money','system_add',$equalMoney,$buyId,$balance,'" . $mark . "')";
                    $this->writeLog('用户id:' . $buyId . '参团返vip流水变动---余额变动sql:' . $sql . ",余额明细变动sql:" . $billSql, 1);
                    $this->_execStatus[] = self::$dbInstance->exec($sql);
                    $this->_execStatus[] = self::$dbInstance->exec($billSql);
                }
            }
        }
    }

    //获取vip抽取流水信息
    private function getApplyMoney($productPrice, $levelList) {
        $pWinMap = [1 => 0, 2 => 1, 3 => 2, 4 => 3];
        $totalPercent = 3;
        $winInfo = [];
        $topVipList = [];
        $preWinPercent = 0;
        foreach ($levelList as $uid => $level) {
            if ($level == 4 && count($topVipList) < 2) {
                $topVipList[] = $uid;
            }
            if ($totalPercent > 0 && $pWinMap[$level] > 0) {
                if (!empty($winInfo)) {
                    $preWinPercent += $winPercent = ($pWinMap[$level] - $preWinPercent) > 0 ? ($pWinMap[$level] - $preWinPercent) : 0;
                } else {
                    $preWinPercent += $winPercent = $pWinMap[$level] ?? 0;
                }
                $winInfo[$uid] = round(bcmul((string)round($winPercent / 100, 2), (string)$productPrice, 3), 2);
                $totalPercent -= $winPercent;
            }
        }
        $equalWinInfo = [];
        if (count($topVipList) > 1) {
            //平级流水
            $endKeys = $topVipList[count($topVipList) - 1];
            $startKeys = $topVipList[0];
            $equalWinInfo[$endKeys] = round($winInfo[$startKeys] * 10 / 100, 2);
        }
        return ['winInfo' => $winInfo, 'equalInfo' => $equalWinInfo];
    }


    //获取上级uid
    private function _getParentId($uid) {

        return self::$redisInstance->hget($this->_cacheKey, $uid)??'';
    }

}